import pandas as pd
import os
import numpy as np
import matplotlib.pyplot as plt
import altair as alt
import altair_saver
Below you will graphs, maps, and images describing streamflow conditions in the water supply areas during the 2023-24 winter season.
os.chdir('C://Users/pmarshal/Documents/Climate-Outlook/monthly-climate')
os.getcwd()
'C:\\Users\\pmarshal\\Documents\\Climate-Outlook\\monthly-climate'
# Import dataset
cap_flow = pd.read_csv('data/cap_flows.csv', parse_dates=['date'])
cap_flow['year'] = pd.DatetimeIndex(cap_flow['date']).year
cap_flow['month'] = pd.DatetimeIndex(cap_flow['date']).month
cap_flow['day'] = pd.DatetimeIndex(cap_flow['date']).day
cap_flow['DOY'] = pd.DatetimeIndex(cap_flow['date']).dayofyear
# Import dataset
cap_hourly = pd.read_csv('data/cap_lakehead_hourly.csv', parse_dates=['datetime'])
cap_hourly.head()
| datetime | flow | return_2 | return_5 | |
|---|---|---|---|---|
| 0 | 2023-01-01 00:00:00 | 28.5 | 358 | 468 |
| 1 | 2023-01-01 01:00:00 | 27.6 | 358 | 468 |
| 2 | 2023-01-01 02:00:00 | 26.7 | 358 | 468 |
| 3 | 2023-01-01 03:00:00 | 25.9 | 358 | 468 |
| 4 | 2023-01-01 04:00:00 | 25.2 | 358 | 468 |
alt.data_transformers.disable_max_rows()
cap_hour_2023 = alt.Chart(cap_hourly).mark_line(color= "darkblue", size= 2, interpolate='basis').encode(
alt.X('monthdate(datetime):T', title=None),
alt.Y('flow:Q', title='Inflow (m^3/s)', scale=alt.Scale(domain=[0, 500])),
tooltip=["datetime:T", "flow"],
)
return_2 = alt.Chart(cap_hourly).mark_line(color='darkgreen', opacity=0.6, strokeDash=[4, 2], size= 1).encode(
alt.X('monthdate(datetime):T', title=None),
alt.Y('return_2:Q', title='Inflow (m^3/s)')
)
return_5 = alt.Chart(cap_hourly).mark_line(color='darkred', opacity=0.6, strokeDash=[4, 2], size= 1).encode(
alt.X('monthdate(datetime):T', title=None),
alt.Y('return_5:Q', title='Inflow (m^3/s)')
)
total_hourly = cap_hour_2023 + return_2 + return_5.properties(width=600)
total_hourly
# Claculate statistics on mean temp column
cap_flow['mean'] = cap_flow.groupby('DOY')['flow'].transform('mean')
cap_flow['max'] = cap_flow.groupby('DOY')['flow'].transform('max')
cap_flow['min'] = cap_flow.groupby('DOY')['flow'].transform('min')
cap_flow['std'] = cap_flow.groupby('DOY')['flow'].transform('std')
cap_flow['sem'] = cap_flow.groupby('DOY')['flow'].transform('sem')
cap_flow['ci95_hi'] = cap_flow['mean'] + 1.96* cap_flow['sem']
cap_flow['ci95_lo'] = cap_flow['mean'] - 1.96* cap_flow['sem']
# Create dataframe with data for the current year
cap_current_year = cap_flow.loc[cap_flow['year'] == 2024]
# Create dataframe with historical data (i.e. not == current year)
cap_past = cap_flow.loc[cap_flow['year'] != 2024]
cap_stats = cap_past.loc[0:364]
alt.data_transformers.disable_max_rows()
cap_rule1 = alt.Chart(pd.DataFrame({
'flow': ['240'],
'color': ['gray']
})).mark_rule(opacity=0.8, strokeDash=[3,3]).encode(
y='flow:Q',
color=alt.Color('color:N', scale=None)
)
cap_rule2 = alt.Chart(pd.DataFrame({
'flow': ['295'],
'color': ['darkblue']
})).mark_rule(opacity=0.8, strokeDash=[3,3]).encode(
y='flow:Q',
color=alt.Color('color:N', scale=None)
)
cap_title = alt.TitleParams(
text='Capilano River above Lakehead (08GA010)',
subtitle="Mean Daily Inflows",
anchor='middle',
fontSize=14,
fontWeight='bold')
cap_2023 = alt.Chart(cap_flow[cap_flow['year'] == 2023], title=cap_title).mark_line(color= "darkblue", size= 2).encode(
alt.X('monthdate(date):T', title=None),
alt.Y('flow:Q', title='Inflow (m^3/s)', scale=alt.Scale(domain=[0, 300])),
tooltip=["date:T", "flow"],
)
cap_mean = alt.Chart(cap_past).mark_line(color='black', opacity=0.6, strokeDash=[4, 2], size= 1).encode(
alt.X('monthdate(date):T', title=None),
alt.Y('mean(flow):Q', title='Inflow (m^3/s)')
)
cap_area2 = alt.Chart(cap_stats).mark_area(color='#919397', opacity=0.6).encode(
alt.X('monthdate(date)'),
alt.Y('ci95_hi:Q'),
alt.Y2('ci95_lo:Q')
)
# Configure the x-axis of the combined chart to display only the first of the month
cap_combined_chart = (cap_area2 + cap_mean + cap_2023 + cap_rule1 + cap_rule2).properties(width=600)
cap_combined_chart
{admonition}
:class: attention
You can find realtime inflow data for Capilano River above Lakehead on the [Water Survey Canada Hydrometric Data website](https://wateroffice.ec.gc.ca/report/real_time_e.html?stn=08GA010)
# Import dataset
seyLH_flow = pd.read_csv('data/seyLH_flow.csv', parse_dates=['date'])
seyLH_flow['year'] = pd.DatetimeIndex(seyLH_flow['date']).year
seyLH_flow['month'] = pd.DatetimeIndex(seyLH_flow['date']).month
seyLH_flow['day'] = pd.DatetimeIndex(seyLH_flow['date']).day
seyLH_flow['DOY'] = pd.DatetimeIndex(seyLH_flow['date']).dayofyear
# Claculate statistics on mean temp column
seyLH_flow['mean'] = seyLH_flow.groupby('DOY')['flow'].transform('mean')
seyLH_flow['max'] = seyLH_flow.groupby('DOY')['flow'].transform('max')
seyLH_flow['min'] = seyLH_flow.groupby('DOY')['flow'].transform('min')
seyLH_flow['std'] = seyLH_flow.groupby('DOY')['flow'].transform('std')
seyLH_flow['sem'] = seyLH_flow.groupby('DOY')['flow'].transform('sem')
seyLH_flow['ci95_hi'] = seyLH_flow['mean'] + 1.96* seyLH_flow['sem']
seyLH_flow['ci95_lo'] = seyLH_flow['mean'] - 1.96* seyLH_flow['sem']
# Create dataframe with data for the current year
sey_current_year = seyLH_flow.loc[seyLH_flow['year'] == 2024]
# Create dataframe with historical data (i.e. not == current year)
sey_past = seyLH_flow.loc[seyLH_flow['year'] != 2024]
sey_stats = sey_past.loc[92:456]
alt.data_transformers.disable_max_rows()
sey_rule1 = alt.Chart(pd.DataFrame({
'flow': ['240'],
'color': ['gray']
})).mark_rule(opacity=0.8, strokeDash=[3,3]).encode(
y='flow:Q',
color=alt.Color('color:N', scale=None)
)
sey_rule2 = alt.Chart(pd.DataFrame({
'flow': ['295'],
'color': ['darkblue']
})).mark_rule(opacity=0.8, strokeDash=[3,3]).encode(
y='flow:Q',
color=alt.Color('color:N', scale=None)
)
sey_title = alt.TitleParams(
text='Seymour River above Lakehead (08GA079)',
subtitle="Mean Daily Inflows",
anchor='middle',
fontSize=14,
fontWeight='bold')
sey_2023 = alt.Chart(seyLH_flow[seyLH_flow['year'] == 2023], title=sey_title).mark_line(color= "darkblue", size= 2).encode(
alt.X('monthdate(date):T', title=None),
alt.Y('flow:Q', title='Inflow (m^3/s)', scale=alt.Scale(domain=[0, 100])),
tooltip=["year:N", "flow"],
)
sey_mean = alt.Chart(sey_past).mark_line(color='black', opacity=0.6, strokeDash=[4, 2], size= 1).encode(
alt.X('monthdate(date):T', title=None),
alt.Y('mean(flow):Q', title='Inflow (m^3/s)')
)
sey_area2 = alt.Chart(sey_stats).mark_area(color='#919397', opacity=0.6).encode(
alt.X('monthdate(date)'),
alt.Y('ci95_hi:Q'),
alt.Y2('ci95_lo:Q')
)
# Configure the x-axis of the combined chart to display only the first of the month
sey_combined_chart = (sey_area2 + sey_mean + sey_2023 + sey_rule1 + sey_rule2).properties(width=600)
sey_combined_chart
{admonition}
:class: attention
You can find realtime inflow data for Seymour River above Lakehead on the [Water Survey Canada Hydrometric Data website](https://wateroffice.ec.gc.ca/report/real_time_e.html?stn=08GA079)
cap_flow2 = pd.read_csv('data/cap_flows.csv')
cap_flow2['date'] = pd.to_datetime(cap_flow2['date'])
cap_flow2['year'] = pd.DatetimeIndex(cap_flow2['date']).year
cap_flow2['month'] = pd.DatetimeIndex(cap_flow2['date']).month
cap_flow2.set_index('date', inplace=True)
cap_monthly_mean = cap_flow2.resample('M').mean()
cap_monthly_mean.reset_index(inplace=True)
cap_monthly_mean['year'] = pd.DatetimeIndex(cap_monthly_mean['date']).year
cap_monthly_mean.head()
| date | flow | year | month | |
|---|---|---|---|---|
| 0 | 1998-01-31 | 34.439032 | 1998 | 1.0 |
| 1 | 1998-02-28 | 32.126071 | 1998 | 2.0 |
| 2 | 1998-03-31 | 18.635484 | 1998 | 3.0 |
| 3 | 1998-04-30 | 11.063333 | 1998 | 4.0 |
| 4 | 1998-05-31 | 24.777419 | 1998 | 5.0 |
#qd_monthly['date'] = pd.to_datetime(qd_monthly[['year', 'month']].assign(day=1))
cap_monthly_mean['mean_flow'] = cap_monthly_mean.groupby('month')['flow'].transform('mean').round(1)
cap_monthly_mean['percent'] = cap_monthly_mean['flow']/cap_monthly_mean['mean_flow'].round(1)
cap_monthly_mean.head()
| date | flow | year | month | mean_flow | percent | |
|---|---|---|---|---|---|---|
| 0 | 1998-01-31 | 34.439032 | 1998 | 1.0 | 28.9 | 1.191662 |
| 1 | 1998-02-28 | 32.126071 | 1998 | 2.0 | 15.7 | 2.046247 |
| 2 | 1998-03-31 | 18.635484 | 1998 | 3.0 | 20.9 | 0.891650 |
| 3 | 1998-04-30 | 11.063333 | 1998 | 4.0 | 22.4 | 0.493899 |
| 4 | 1998-05-31 | 24.777419 | 1998 | 5.0 | 27.1 | 0.914296 |
yr_2023 = cap_monthly_mean.loc[cap_monthly_mean['year'] == 2023]
yr_2023.to_csv('yr_2023_flow.csv', index=False)
# Filter the data for the current year (2023)
#data_2023 = qd_monthly[qd_monthly['year'] == 2023]
data_all = cap_monthly_mean[cap_monthly_mean['year'] != 2023]
title2 = alt.TitleParams(
text='Capilano River above Lakehead (08GA010)',
subtitle="Average Monthly Inflows",
anchor='middle',
fontSize=14,
fontWeight='bold')
cap_monthly_2023 = alt.Chart(yr_2023).mark_tick(size=14, thickness=3, color='green').encode(
alt.X('month(date):O'),
alt.Y('flow:Q'),
tooltip=[alt.Tooltip('date', title='Date'), alt.Tooltip('flow', title='Inflow')]
).properties(width=400, height=250)
cap_boxplot = alt.Chart(data_all).mark_boxplot(opacity=0.7).encode(
alt.X('month(date):O', title=' '),
alt.Y('flow:Q', title='River Inflow (m^3/s)')
).properties(width=400, height=250)
cap_plots = cap_boxplot + cap_monthly_2023
cap_plots
# Create a chart for 'TA_Anomaly'
flow_anomaly_chart = alt.Chart(yr_2023).mark_bar(color='darkgreen').encode(
x=alt.X('percent:Q', title=None, axis=alt.Axis(format='%')),
y=alt.Y('monthdate(date):O', title=None, axis=alt.Axis(format='%b')),
tooltip=[alt.Tooltip('date', title='Date'), alt.Tooltip('percent', title='Percent')]
).properties(
title = 'Percent of Normal',width=100, height=250
)
rule1 = alt.Chart(pd.DataFrame({
'percent': ['1'],
'color': ['gray']
})).mark_rule(opacity=0.8, strokeDash=[3,3]).encode(
x='percent:Q',
color=alt.Color('color:N', scale=None)
)
text_percent = flow_anomaly_chart.mark_text(
align='left',
baseline='middle',
size=10,
dx=3 # Nudges text to right so it doesn't appear on top of the bar
).encode(
text=alt.Text('percent:Q', format='.0%'), # Format as percentage
)
anomaly_text = flow_anomaly_chart + text_percent
anomaly = anomaly_text + rule1
month_flow = cap_plots | anomaly
month_flow
sey_flow2 = pd.read_csv('data/seyLH_flow.csv')
sey_flow2['date'] = pd.to_datetime(sey_flow2['date'])
sey_flow2.set_index('date', inplace=True)
sey_monthly_mean = sey_flow2.resample('M').mean()
sey_monthly_mean.reset_index(inplace=True)
sey_monthly_mean['year'] = pd.DatetimeIndex(sey_monthly_mean['date']).year
sey_yr_2023 = sey_monthly_mean.loc[sey_monthly_mean['year'] == 2023]
title3 = alt.TitleParams(
text='Seymour River above Lakehead (08GA010)',
subtitle="Average Monthly Inflows",
anchor='middle',
fontSize=14,
fontWeight='bold')
sey_monthly_2023 = alt.Chart(sey_yr_2023).mark_tick(size=14, thickness=3, color='green').encode(
alt.X('month(date):O'),
alt.Y('flow:Q'),
tooltip=[alt.Tooltip('date', title='Date'), alt.Tooltip('flow', title='Inflow')]
)
sey_boxplot = alt.Chart(sey_monthly_mean, title=title3).mark_boxplot(opacity=0.7).encode(
alt.X('month(date):O', title=' '),
alt.Y('flow:Q', title='River Inflow (m^3/s)')
)
sey_plots = sey_boxplot + sey_monthly_2023
sey_plots.properties(width=600, height=200)
{note}
Backwatering occurs at the Seymour Lakehead site in the spring (May and June) when the reservoir is full. This causes elevated water levels and inaccurate inflow readings.
vol = pd.read_csv('data/cap_volume.csv', parse_dates=['date'])
vol['DOY'] = pd.DatetimeIndex(vol['date']).dayofyear
vol['month'] = pd.DatetimeIndex(vol['date']).month
vol['year'] = pd.DatetimeIndex(vol['date']).year
vol['tick_date'] = pd.to_datetime(vol['DOY'], format='%j').dt.strftime('%b-%d')
vol['mean'] = vol.groupby('wtr_day')['volume'].transform('mean').round(2)
vol['max'] = vol.groupby('wtr_day')['volume'].transform('max').round(2)
vol['min'] = vol.groupby('wtr_day')['volume'].transform('min').round(2)
vol['std'] = vol.groupby('wtr_day')['volume'].transform('std').round(2)
vol['sem'] = vol.groupby('wtr_day')['volume'].transform('sem').round(2)
vol['ci95_hi'] = vol['mean'] + 1.96* vol['sem']
vol['ci95_lo'] = vol['mean'] - 1.96* vol['sem']
vol['ci95_hi'] = vol['ci95_hi'].round(2)
vol['ci95_lo'] = vol['ci95_lo'].round(2)
# Assuming vol is your DataFrame
vol['percentile_5th'] = vol.groupby('wtr_day')['volume'].transform(lambda x: np.percentile(x, 5))
vol['percentile_95th'] = vol.groupby('wtr_day')['volume'].transform(lambda x: np.percentile(x, 95))
rank = vol.groupby(['wtr_year'])['volume'].sum().rank()
vol.head()
| date | wtr_year | wtr_day | volume | DOY | month | year | tick_date | mean | max | min | std | sem | ci95_hi | ci95_lo | percentile_5th | percentile_95th | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2002-10-01 | 2003 | 1 | 0.1 | 274 | 10 | 2002 | Oct-01 | 1.38 | 9.7 | 0.1 | 2.35 | 0.50 | 2.36 | 0.40 | 0.20 | 5.195 |
| 1 | 2002-10-02 | 2003 | 2 | 0.3 | 275 | 10 | 2002 | Oct-02 | 2.44 | 13.0 | 0.3 | 3.74 | 0.80 | 4.01 | 0.87 | 0.31 | 11.040 |
| 2 | 2002-10-03 | 2003 | 3 | 0.4 | 276 | 10 | 2002 | Oct-03 | 3.53 | 14.8 | 0.4 | 4.38 | 0.93 | 5.35 | 1.71 | 0.42 | 13.625 |
| 3 | 2002-10-04 | 2003 | 4 | 0.6 | 277 | 10 | 2002 | Oct-04 | 4.66 | 16.0 | 0.5 | 5.28 | 1.13 | 6.87 | 2.45 | 0.62 | 15.595 |
| 4 | 2002-10-05 | 2003 | 5 | 0.7 | 278 | 10 | 2002 | Oct-05 | 5.54 | 18.7 | 0.6 | 6.04 | 1.29 | 8.07 | 3.01 | 0.73 | 17.080 |
alt.data_transformers.disable_max_rows()
vert_line = alt.Chart(pd.DataFrame({
'wtr_day': [61],
'color': ['black']
})).mark_rule(opacity=0.6, strokeDash=[3,3]).encode(
x='wtr_day',
color=alt.Color('color:N', scale=None)
)
# Add text annotation
text1 = alt.Chart().mark_text(
text='Nov. 30', # Replace with your desired text
align='left',
size=10,
baseline='middle',
color='black',
dx=94 # adjust the position of the text
).encode(
x=alt.value(10), # Adjust the x-position of the text box
y=alt.value(10) # Adjust the y-position of the text box
)
# Create title
title5 = alt.TitleParams(
text='Capilano River at Lakehead (08GA010)',
subtitle="Cumulative inflow during the water year",
anchor='middle',
fontSize=14,
fontWeight='bold')
# Create a selection for the year
#year_selection = alt.selection_single(
# name='Select',
## fields=['year'],
# bind=alt.binding_select(options=list(vol['year'].unique()), name='Select Year '),
# init={'year': 2023} # Initial selected year
#)
#scale=alt.Scale(domain=[0,365], nice=False)
# Create a line chart using Altair
#chart6 = alt.Chart(vol).mark_line().encode(
# alt.X('DOY'),
# alt.Y('volume:Q', title='Cumulative Inflow (billion litres)'),
# color=alt.condition(year_selection, 'year:N', alt.value('gray'), title='Year'),
# strokeWidth=alt.condition(year_selection, alt.value(2.5), alt.value(1)),
# opacity=alt.condition(year_selection, alt.value(1.0), alt.value(0.6)),
# tooltip=alt.condition(year_selection, "volume", alt.value(''))
#).add_selection(
# year_selection
#).properties(
# width=600
#)
#chart6